home *** CD-ROM | disk | FTP | other *** search
/ NeXT Enterprise Objects Framework 1.1 / NeXT Enterprise Objects Framework 1.1.iso / NextDeveloper / Examples / EnterpriseObjects / DistributedEO / DEOClient.subproj / DEONotificationCenter.m < prev    next >
Encoding:
Text File  |  1995-02-17  |  7.1 KB  |  237 lines

  1. /*
  2.    DEONotificationCenter.m created by enoyau on Fri 13-Jan-1995
  3.  
  4.    You may freely copy, distribute, and reuse the code in this example.
  5.    NeXT disclaims any warranty of any kind, expressed or implied, as to its
  6.    fitness for any particular use.
  7. */
  8.  
  9. #import "DEONotificationCenter.h"
  10. #import "DEONotification.h"
  11. #import "DEOServerMonitor.h"
  12. #import <foundation/NSException.h>
  13.  
  14. #import <libc.h>
  15.  
  16. NSString *DEOUpdate = @"DEOUpdate";
  17. NSString *DEOInsert = @"DEOInsert";
  18. NSString *DEODelete = @"DEODelete";
  19.  
  20. @interface DEONotificationCenter(Communication) <DEOClient>
  21. - (void)registerAgain:(NSNotification *)note;
  22. @end
  23.  
  24. // Holder object to allow the server to retain the proxy to
  25. // a DEONotificationCenter without retaining the center itself.
  26. // See comment in initWithDatabaseChannel:entity:
  27. @interface DEONotificationCenterHolder : NSObject <DEOClient>
  28. {
  29.     DEONotificationCenter *center;
  30. }
  31. - initWithNonRetainedObject:(DEONotificationCenter *)aCenter;
  32. @end
  33.  
  34.  
  35. @implementation DEONotificationCenter
  36.  
  37. static NSString *localHostname = nil;
  38.  
  39. + initialize
  40. {
  41.     if(!localHostname) {
  42.         char DEOHostname[1024];
  43.  
  44.         gethostname(DEOHostname, 1024);
  45.         localHostname = [[NSString alloc] initWithCString:DEOHostname];
  46.     }
  47.     return self;
  48. }
  49.  
  50. + (NSString *)localHostname
  51. {
  52.     return localHostname;
  53. }
  54.  
  55. - initWithDatabaseChannel:(EODatabaseChannel *)aDatabaseChannel 
  56.                    entity:(EOEntity *)anEntity
  57. {
  58.     NSArray *objs;
  59.     NSArray *keys;
  60.     
  61.     [super init];
  62.  
  63.     // localCenter is used for notification.
  64.     localCenter = [[NSNotificationCenter alloc] init];
  65.     entity = [anEntity retain];
  66.     databaseChannel = [aDatabaseChannel retain];
  67.  
  68.     // Build the unique identifier for the DEONotificationCenter
  69.     objs = [NSArray arrayWithObjects:
  70.         localHostname,
  71.         [NSString stringWithFormat:@"%d", getpid()],
  72.         [anEntity name],
  73.         [NSString stringWithFormat:@"%x", self],
  74.         0];
  75.  
  76.     keys = [NSArray arrayWithObjects:
  77.         @"hostname",
  78.         @"pid",
  79.         @"entity",
  80.         @"self",
  81.         0];
  82.  
  83.     localID = [[NSDictionary dictionaryWithObjects:objs forKeys:keys] retain];
  84.  
  85.     // Register self for notifications from monitor
  86.     monitor = [[DEOServerMonitor serverMonitor] retain];
  87.     [[NSNotificationCenter defaultCenter] addObserver:self
  88.                                              selector:@selector(registerAgain:)
  89.                                      notificationName:DEOServerReinitialize
  90.                                                object:monitor];
  91.  
  92.     // We need to pass the server a pointer to our object, but it cannot
  93.     // retain it, or a cycle will be created.  Unfortunately, the server
  94.     // MUST retain the object we pass it or the proxy on the server side
  95.     // will be released.  The solution is to pass the server an "holder"
  96.     // object that it can retain (thus retaining the proxy) without
  97.     // retaining us (thus avoiding a cycle).  This holder must pass on
  98.     // messages to our actual instance.
  99.     container =
  100.         [[DEONotificationCenterHolder alloc] initWithNonRetainedObject:self];
  101.  
  102.     [self registerAgain:nil];
  103.     
  104.     return self;
  105. }
  106.  
  107. - (void)dealloc
  108. {
  109.     [localCenter release];
  110.     [entity release];
  111.     [databaseChannel release];
  112.     [localID release];
  113.     NS_DURING
  114.         [[monitor server] unregisterClient:(id <DEOClient>)container];
  115.     NS_HANDLER
  116.         NSLog(@"Failed to send remote method unregisterClient: to server.\n");
  117.     NS_ENDHANDLER
  118.     [container release];
  119.     [monitor release];
  120.     [super dealloc];
  121.     return;
  122. }
  123.  
  124. - (void)addObserver:observer
  125.            selector:(SEL)selector
  126.    notificationName:(NSString *)notificationName
  127.              object:object
  128. {
  129.     [localCenter addObserver:observer
  130.                     selector:selector
  131.             notificationName:notificationName
  132.                       object:object];
  133. }
  134.  
  135. - (void)removeObserver:observer
  136.       notificationName:(NSString *)notificationName
  137.                 object:object;
  138. {
  139.     [localCenter removeObserver:observer
  140.                notificationName:notificationName
  141.                          object:object];
  142. }
  143.  
  144. - (void)removeObserver:observer
  145. {
  146.     [localCenter removeObserver:observer];
  147. }
  148.  
  149. - (void)postNotificationName:(NSString *)notificationName object:object
  150. {
  151.     [self postNotificationName:notificationName object:object userInfo:nil];
  152. }
  153.  
  154. - (void)postNotificationName:(NSString *)name
  155.                       object:object
  156.                     userInfo:(NSDictionary *)userInfo;
  157. {
  158.     NSMutableDictionary *info = [NSMutableDictionary dictionary];
  159.     NSDictionary *primaryKey =
  160.         [entity primaryKeyForRow:[[[databaseChannel databaseContext] database] snapshotForObject:object]];
  161.  
  162.     // Encodes the enterprise object in a dictionary with the primary key.
  163.     [info setObject:primaryKey forKey:@"primaryKey"];
  164.     [info setObject:name       forKey:@"notificationName"];
  165.     [info setObject:localID    forKey:@"sender"];
  166.  
  167.     NS_DURING
  168.         [[monitor server] dispatchInformation:info
  169.                                        forKey:[entity name]
  170.                                      userInfo:userInfo];
  171.     NS_HANDLER
  172.             NSLog(@"Failed to send remote method dispatchInformation:forKey:userInfo: to server.\n");
  173.     NS_ENDHANDLER
  174. }
  175.  
  176. @end
  177.  
  178. @implementation DEONotificationCenter(Communication)
  179.  
  180. - (oneway)dispatchInformation:(NSDictionary *)info
  181.                        forKey:(NSString *)key
  182.                      userInfo:(NSDictionary *)userInfo
  183. {
  184.     // Decodes the enterprise object from information over the wire
  185.     id database = [[databaseChannel databaseContext] database];
  186.     id eoObject = [database objectForPrimaryKey:[info objectForKey:@"primaryKey"]
  187.                                          entity:entity];
  188.  
  189.     if(!eoObject) {
  190.         // Creates an EOFault if object does not exist yet
  191.         [EOFault objectFaultWithPrimaryKey:[info objectForKey:@"primaryKey"]
  192.                                     entity:entity
  193.                            databaseChannel:databaseChannel
  194.                                       zone:NSDefaultMallocZone()];
  195.     }
  196.  
  197.     [localCenter postNotification:
  198.         [DEONotification notificationWithName:[info objectForKey:@"notificationName"]
  199.                                        object:eoObject
  200.                                      userInfo:userInfo
  201.                                       isLocal:[[info objectForKey:@"sender"] isEqual:localID]]];
  202.  
  203.     return;
  204. }
  205.  
  206. // Is called at init time or when the server has died.
  207. - (void)registerAgain:(NSNotification *)note
  208. {
  209.     NS_DURING
  210.         // Register as entity user in the distributed server
  211.         [[monitor server] registerClient:(id <DEOClient>)container forKey:[entity name]];
  212.     NS_HANDLER
  213.         NSLog(@"Failed to send remote method registerClient:forKey: to server.\n");
  214.     NS_ENDHANDLER
  215. }
  216.  
  217. @end
  218.  
  219. @implementation DEONotificationCenterHolder
  220.  
  221. - initWithNonRetainedObject:(DEONotificationCenter *)aCenter
  222. {
  223.     [super init];
  224.     center = aCenter;
  225.     return self;
  226. }
  227.  
  228. - (oneway)dispatchInformation:(NSDictionary *)info
  229.                        forKey:(NSString *)key
  230.                      userInfo:(NSDictionary *)userInfo
  231. {
  232.     [center dispatchInformation:info
  233.                          forKey:key
  234.                        userInfo:userInfo];
  235. }
  236. @end
  237.